package board.animation.render;

import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.util.HashMap;
import java.util.Map;

import static java.lang.Math.PI;

public class SpinningOccupantRender<T> implements AnimatedOccupantRender<T> {
	public static final double SQRT2 = Math.sqrt(2);
	public static final double SQRT2MIN1 = SQRT2 - 1.0;
	private T occupant;
	private int speed;
	private int step;
	private double rotation;
	private Map<Double, Image> cache = new HashMap<Double, Image>();
	private Image rendered;
	private boolean clock;

	@Override
	public void setOccupant(T occupant) {this.occupant = occupant;}
	@Override
	public T getOccupant() {return occupant;}
	@Override
	public boolean isComplete() {return step >= speed;}
	@Override
	public void setSpeed(int speed) {this.speed = speed;}
	@Override
	public void start() {step = 0;}

	@Override
	public void next() {
		if(!isComplete()) {
			step++;
			rotation = step * 2 * PI / speed;
			if(clock)
				rotation = -rotation;
		}
	}
	@Override
	public Image getNewImage(Image normal, ImageObserver observer) {
		if(rendered != null) {
			if(!rendered.equals(normal)) {
				cache.clear();
				rendered = normal;
			}
		} else
			rendered = normal;
		Image image = cache.get(rotation);
		int width = (int) (normal.getWidth(observer) * SQRT2);
		int height = (int) (normal.getHeight(observer) * SQRT2);
		if(image != null && image.getWidth(observer) == width && image.getHeight(observer) == height)
			return image;
		image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
		Graphics2D g = (Graphics2D)image.getGraphics();
		g.rotate(rotation, normal.getWidth(observer) * SQRT2 / 2, normal.getHeight(observer) * SQRT2 / 2);
		g.drawImage(normal, (int) (SQRT2MIN1 * normal.getWidth(observer) / 2), (int) (SQRT2MIN1 * normal.getHeight(observer) / 2), observer);
		g.dispose();
		return image;
	}
	
	public void setCounterClockwise(boolean clockwise) {clock = clockwise;}
	public boolean getCounterClockwise() {return clock;}
}
